namespace ClassyBlog.Specs.Acceptance
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text.RegularExpressions;

    using WatiN.Core;

    public static class Extensions
    {
        private static readonly Regex stripHTML = new Regex(
            "<\\S[^><]*>",
            RegexOptions.Singleline |
            RegexOptions.Multiline |
            RegexOptions.CultureInvariant |
            RegexOptions.Compiled);

        private static readonly Regex matchAlphanumeric = new Regex(
            "^[a-zA-Z0-9_\\-]*$",
            RegexOptions.Singleline |
            RegexOptions.CultureInvariant |
            RegexOptions.Compiled);

        private static readonly char[] wordSeparators =
            new[] { ' ', '.', ',', ';', '\'', '"', '\n' };

        public static void Visit(
            this Browser instance, string relativeUrl = "/")
        {
            var url = relativeUrl ?? string.Empty;

            if (url.StartsWith("/", StringComparison.Ordinal))
            {
                url = url.Length > 1 ? url.Substring(1) : string.Empty;
            }

            var fullUrl = string.Format(
                "http://localhost:{0}/{1}", Bootstrapper.ServerPort, url);

            instance.GoTo(fullUrl);
            instance.WaitForComplete(60 * 1000); // 1 Minute
        }

        public static Element Select(
            this IElementContainer instance, string selector)
        {
            return instance.Element(Find.BySelector(selector));
        }

        public static bool SimilarTo(this string instance, string target)
        {
            if (string.IsNullOrWhiteSpace(instance))
            {
                return false;
            }

            if (string.IsNullOrWhiteSpace(target))
            {
                return false;
            }

            var trimmedSource = instance.Trim();
            var trimedTarget = target.Trim();

            if (trimmedSource.Equals(trimedTarget))
            {
                return true;
            }

            var stripedSource = stripHTML.Replace(trimmedSource, string.Empty);
            var stripedTarget = stripHTML.Replace(trimedTarget, string.Empty);

            if (stripedSource.Equals(stripedTarget))
            {
                return true;
            }

            Func<string, IList<string>> getWords = v =>
                v.Split(wordSeparators, StringSplitOptions.RemoveEmptyEntries)
                 .Where(w => matchAlphanumeric.IsMatch(w))
                 .ToList();

            var sourceWords = getWords(stripedSource);
            var targetWords = getWords(stripedTarget);

            if (sourceWords.Count != targetWords.Count)
            {
                return false;
            }

            for (int i = 0; i < sourceWords.Count; i++)
            {
                var sourceWord = sourceWords[i];
                var targetWord = targetWords[i];

                if (sourceWord.Equals(targetWord))
                {
                    continue;
                }

                return false;
            }

            return true;
        }
    }
}